/*
 ========================================================================
 Name        : ImageGridDisplay.cpp
 Author      : Jose Thachil M
 Copyright   : Your copyright notice
 Description : This class is used to display thumbnail view of images in grid format.
 ========================================================================
 */
#include <AknLists.h>         // for AknListBoxLayouts
#include <pathinfo.h>         // for PathInfo
#include <ImageConversion.h>  // for CImageDecoder
#include <gulicon.h>          // for CGulIcon
#include "ImageGridDisplay.h"

CImageConvertor* CImageConvertor::NewL(MGridInterface& aGridInterface)
	{
	CImageConvertor* self = CImageConvertor::NewLC(aGridInterface);
	CleanupStack::Pop(self);
	return self;
	}

// -----------------------------------------------------------------------------
// CImageConvertor::NewLC()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CImageConvertor* CImageConvertor::NewLC(MGridInterface& aGridInterface)
	{
	CImageConvertor* self = new (ELeave) CImageConvertor(aGridInterface);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}
void CImageConvertor::ConstructL()
	{
	User::LeaveIfError(iFsSession.Connect());

	}
CImageConvertor::CImageConvertor(MGridInterface& aGridInterface) :
	                             CActive(EPriorityStandard), iGridInterface(aGridInterface),iErrorStatus(EFalse)
	{
	CActiveScheduler::Add(this);
	}
CImageConvertor::~CImageConvertor()
	{  
	Cancel();
	delete iImageDecoder;
	if(iErrorStatus)
		{
		RDebug::Printf("Memory Leak Find In delete of CImageConvertor = %x",iCreatedFbsBitmap);
		delete iCreatedFbsBitmap;
		}
	iBitmapPtr.Close();
	iFsSession.Close();
	}

void CImageConvertor::StartImageConversionL(TFileName& aFilepath)
	{
	delete iImageDecoder;
	iImageDecoder = NULL;
	
	iImageDecoder = CImageDecoder::FileNewL(iFsSession, aFilepath, 
			                                CImageDecoder::EOptionAlwaysThread);
	
	RDebug::Printf("Memory Leak Find Address of iImageDecoder = %x",iImageDecoder);

	CFbsBitmap* aBitmap = new (ELeave) CFbsBitmap();
	RDebug::Printf("Memory Leak Find Address of aBitmap == %x",aBitmap);
	CleanupStack::PushL(aBitmap);
	iBitmapPtr.AppendL(aBitmap);
	CleanupStack::Pop(aBitmap);
	
	iCreatedFbsBitmap = aBitmap;
	
	RDebug::Printf("Memory Leak Find Address of iCreatedFbsBitmap = %x",iCreatedFbsBitmap);

	
	User::LeaveIfError(aBitmap->Create(iImageDecoder->FrameInfo().iOverallSizeInPixels,
			           iImageDecoder->FrameInfo().iFrameDisplayMode));
	iImageDecoder->Convert(&iStatus, *aBitmap);
	SetActive();

	}
void CImageConvertor::DoCancel()
	{
	//cancel image conversion
	iImageDecoder->Cancel();
	}

// ----------------------------------------------------------------------------
// CImageConvertor::RunL()
// ----------------------------------------------------------------------------
void CImageConvertor::RunL()
	{
	//TODO need to take care of no memory scenario
	if (iStatus.Int() == KErrNone)
		{
		iGridInterface.UpdateGrid(*(iBitmapPtr.operator[](iBitmapPtr.Count()- 1)));
		}
	}

// Called if RunL() leaves, aError contains the leave code.
TInt CImageConvertor::RunError(TInt aError)
    {
    // Logs the error.
    RDebug::Printf("CImageConvertor::RunError = %d", aError);  
    iErrorStatus = ETrue;
    iGridInterface.ShowErrorMessage(aError);
    return KErrNone;                   
    }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CImageGridDispaly* CImageGridDispaly::NewL(const TRect& aRect)
	{
	CImageGridDispaly* self = CImageGridDispaly::NewLC(aRect);
	CleanupStack::Pop(self);
	return self;
	}

// -----------------------------------------------------------------------------
// CImageGridDispaly::NewLC()
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CImageGridDispaly* CImageGridDispaly::NewLC(const TRect& aRect)
	{
	CImageGridDispaly* self = new (ELeave) CImageGridDispaly();
	CleanupStack::PushL(self);
	self->ConstructL(aRect);
	return self;
	}

CImageGridDispaly::CImageGridDispaly():iArrayIndex(0),iErrorStatus(EFalse)
	{
	}

// -----------------------------------------------------------------------------
// CImageGridDispaly::~CImageGridDispaly()
// Destructor
// -----------------------------------------------------------------------------
//
CImageGridDispaly::~CImageGridDispaly()
	{
	RDebug::Printf("In Desctuctor of CImageGridDispaly 1");
	if(iGrid)
		{
		MDesCArray* array = iGrid->Model()->ItemTextArray();
		CDesCArray* cArray = ( CDesCArray* )array;
		
		// Delete data from array
		if (iGrid->GridModel()->NumberOfData() > 0)
			{
			cArray->Delete(0, iGrid->GridModel()->NumberOfData());
			}
		delete cArray;
		}
	
	if(iArrayicons)
		{
		//if error occured during conversion
		if(iErrorStatus)
			{
			TInt count = 0;
			RPointerArray<CGulIcon>   removeGulIcon;
			while(iArrayIndex-1 > count)
				{
				CGulIcon* aGulIcon = iArrayicons->At(count);
				removeGulIcon.AppendL(aGulIcon);
				count++;
				}
			TInt numberOfData = iArrayicons->Count();
			iArrayicons->Delete(0,numberOfData);
			removeGulIcon.ResetAndDestroy();	
			}
		else
			{
			iArrayicons->ResetAndDestroy();
			}
				
		}
	
	delete iImageConvertor;
	delete iGrid;
	
	delete iDefaultGulIcon;
	iFiles.Close();
	RDebug::Printf("In Desctuctor of CImageGridDispaly 3");
	}

void CImageGridDispaly::SetGridTextFont()
	{
	CGraphicsDevice* screenDevice = iCoeEnv->ScreenDevice();
	TFontSpec fontSpec2 = CCoeEnv::Static()->NormalFont()->FontSpecInTwips();
	fontSpec2.iTypeface.iName = _L("Latin");
	fontSpec2.iHeight = 80;
	CFont* fontText;
	screenDevice->GetNearestFontInTwips(fontText, fontSpec2);
	iGrid->ItemDrawer()->FormattedCellData()->SetSubCellFontL(1, fontText);
	CCoeEnv::Static()->ReleaseScreenFont(fontText);
	}
void CImageGridDispaly::ConstructL(const TRect& aRect)
	{
	iImageConvertor = CImageConvertor::NewL(*this);
	
	TFileName PhoneMemoryPath = PathInfo::PhoneMemoryRootPath(); 
	PhoneMemoryPath.Append(PathInfo::ImagesPath());
	ReadImageDirectoryL(PhoneMemoryPath);
	
	TFileName MemoryCardPath = PathInfo::MemoryCardRootPath(); 
	MemoryCardPath.Append(PathInfo::ImagesPath());
	ReadImageDirectoryL(MemoryCardPath);
	
    CreateWindowL();	
   	SetRect(CEikonEnv::Static()->EikAppUi()->ClientRect());
      	
   	ActivateL();
   	DrawNow();
	}
// -----------------------------------------------------------------------------
// CImageGridDispaly::SizeChanged()
// Called by framework when the view size is changed.
// -----------------------------------------------------------------------------
//
void CImageGridDispaly::SizeChanged()
	{
	// Need to call in Trap since SizeChanged() is not supposed to be a leaving function.
	TRAP_IGNORE(MakeGridBoxL());
	CGraphicsDevice* screenDevice = iCoeEnv->ScreenDevice();
	TFontSpec fontSpec2 = CCoeEnv::Static()->NormalFont()->FontSpecInTwips();
	fontSpec2.iTypeface.iName=_L("Latin");
	fontSpec2.iHeight = 80;
	CFont* fontText; 
	screenDevice->GetNearestFontInTwips(fontText,fontSpec2);
	iGrid->ItemDrawer()->FormattedCellData()->SetSubCellFontL(1,fontText);
	CCoeEnv::Static()->ReleaseScreenFont(fontText);
	CCoeControl::SizeChanged();
	}
// ---------------------------------------------------------
// CImageGridDispaly::HandleResourceChange()
// Called by framework when layout is changed.
// Support for scalable UI
// ---------------------------------------------------------
//
void CImageGridDispaly::HandleResourceChange(TInt aType)
	{
	if ( aType==KEikDynamicLayoutVariantSwitch )
		{
		TRect rect;
		AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EMainPane, rect );
		SetRect( rect );
		}
	CCoeControl::HandleResourceChange( aType );
	}
// -----------------------------------------------------------------------------
// CImageGridDispaly::Draw()
// Draws the display.
// -----------------------------------------------------------------------------
//
void CImageGridDispaly::Draw(const TRect& /*aRect*/) const
	{
	CWindowGc& gc = SystemGc();
	gc.Clear(Rect());
	}
// -----------------------------------------------------------------------------
// CImageGridDispaly::CountComponentControls()
// Called by the framework in compound controls    
// @return The number of controls in this CSimpleGridContainer
// -----------------------------------------------------------------------------
//
TInt CImageGridDispaly::CountComponentControls() const
	{
	return 1; // return number of controls inside this container
	}

// -----------------------------------------------------------------------------
// CImageGridDispaly::ComponentControl
// Called by the framework in compound controls    
// @param The index of the control to return
// @return The control for aIndex
// -----------------------------------------------------------------------------
//
CCoeControl* CImageGridDispaly::ComponentControl(TInt aIndex) const
	{
	switch (aIndex)
		{
		case 0:
			return iGrid;
		default:
			return NULL;
		}
	}

void CImageGridDispaly::FocusChanged(TDrawNow aDrawNow)
	{
	CCoeControl::FocusChanged(aDrawNow);
	
	if (iGrid)
		{
		iGrid->SetFocus(IsFocused(), aDrawNow);
		}
	}

void CImageGridDispaly::SetEmptyTextL()
	{
	_LIT(KNoPhoto, "No Photos");
	iGrid->SetEmptyGridTextL(KNoPhoto);
	}
void CImageGridDispaly::MakeGridBoxL()
	{
	TInt MySetIndex(0);
	 
	if(iGrid)
		{
		MySetIndex = iGrid->CurrentItemIndex();
		iGrid->MakeVisible( EFalse );
		}
	if(iGrid)
		{
		MDesCArray* array = iGrid->Model()->ItemTextArray();
		CDesCArray* cArray = ( CDesCArray* )array;
		
		// Delete data from array
		if (iGrid->GridModel()->NumberOfData() > 0)
			{
			cArray->Delete(0, iGrid->GridModel()->NumberOfData());
			}
		delete cArray;
		}
	
	if(iArrayicons)
		{
		//if error occured during conversion
		if(iErrorStatus)
			{
			TInt count = 0;
			RPointerArray<CGulIcon>   removeGulIcon;
			while(iArrayIndex-1 > count)
				{
				CGulIcon* aGulIcon = iArrayicons->At(count);
				removeGulIcon.AppendL(aGulIcon);
				count++;
				}
			TInt numberOfData = iArrayicons->Count();
			iArrayicons->Delete(0,numberOfData);
			removeGulIcon.ResetAndDestroy();	
			}
		else
			{
			iArrayicons->ResetAndDestroy();
			}
				
		}
	
	iArrayIndex  = 0;
	iErrorStatus = EFalse;
					
	delete iDefaultGulIcon;
	iDefaultGulIcon = NULL;
							
	delete iGrid;
	iGrid = NULL;
		
	if(iArrayicons)
		{
		//delete iArrayicons;
		}
		
	iGrid = new( ELeave ) CAknGrid;
	RDebug::Printf("Memory Leak Find Address of iGrid = %x",iGrid);
	     
	CAknGridM* GridViewM = new( ELeave ) CAknGridM;
	iGrid->SetModel( GridViewM );
   //EAknListBoxSelectionGrid
	iGrid->ConstructL( this,EAknListBoxMarkableGrid  );
	iGrid->SetContainerWindowL(*this); // MEikListBoxObserver
	
	TRect MyRect(Rect());
	iGrid->SetRect(MyRect);
 
	TInt NumH = (MyRect.Height() / 100);
	TInt NumW = (MyRect.Width() / 100);
 
	if(NumH < 3)
	{
		NumH = 3;
	}
 
	if(NumW < 3)
	{
		NumW = 3;
	}
 
	TSize SizeOfItems;
 
	SizeOfItems.iWidth = (( MyRect.iBr.iX - MyRect.iTl.iX ) / NumW)-9;
	SizeOfItems.iHeight = (( MyRect.iBr.iY - MyRect.iTl.iY )/ NumH)-9;
 
	iGrid->SetLayoutL(EFalse,ETrue,ETrue,NumW,NumH,SizeOfItems);
 
	iGrid->SetPrimaryScrollingType(CAknGridView::EScrollIncrementLineAndLoops);
	iGrid->SetSecondaryScrollingType(CAknGridView::EScrollIncrementLineAndLoops);
	iGrid->SetCurrentDataIndex(0);
 
	
	iArrayicons = new( ELeave ) CAknIconArray(2);
	
	const CFont* MyUseFont = AknLayoutUtils::FontFromId(EAknLogicalFontSecondaryFont);
	
	TPoint TxtStartPoint(0,(SizeOfItems.iHeight - (MyUseFont->HeightInPixels() + 3)));
	TPoint TxtEndddPoint(SizeOfItems.iWidth, SizeOfItems.iHeight);
 
	TPoint StartIcon(0,0);
	TPoint EnddIcon(SizeOfItems.iWidth, (TxtStartPoint.iY));
	TPoint EnddIcon1(SizeOfItems.iWidth, (TxtStartPoint.iY));
 
	TSize IconsSize((((EnddIcon.iX - StartIcon.iX) * 9) / 10),(((EnddIcon.iY - StartIcon.iY) * 9) / 10));
 
	
	iGrid->Model()->SetItemTextArray(GetArrayL(iArrayicons, IconsSize));
	iGrid->Model()->SetOwnershipType(ELbmDoesNotOwnItemArray);
	iGrid->ItemDrawer()->FormattedCellData()->SetIconArrayL(iArrayicons);
	
	iGrid->Model()->SetOwnershipType(ELbmDoesNotOwnItemArray);
	 
	iGrid->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EAuto, CEikScrollBarFrame::EAuto);
 
	iGrid->HandleItemAdditionL();
	
	iGrid->SetEmptyGridTextL( _L("No Photos Found sorry") );
 
	AknListBoxLayouts::SetupStandardGrid(*iGrid);
 
	AknListBoxLayouts::SetupFormGfxCell(*iGrid, iGrid->ItemDrawer(),
										0,
										6,
										6,
										0,
										0,
										SizeOfItems.iWidth-12,((EnddIcon.iY - StartIcon.iY)), 
										StartIcon, EnddIcon1);
	
 
	TInt BaseLine = (TxtEndddPoint.iY - MyUseFont->BaselineOffsetInPixels() - 8);
 
	AknListBoxLayouts::SetupFormTextCell(*iGrid, iGrid->ItemDrawer(),
										 1,  MyUseFont, 
										 215, 
										 3, 
										 0, 
										 BaseLine,
										 SizeOfItems.iWidth, 
										 CGraphicsContext::ECenter,
										 TxtStartPoint, 
										 TxtEndddPoint
										 );
 
	
	TRgb textColor; // text color when not highlighted
	MAknsSkinInstance* skin = AknsUtils::SkinInstance();
	AknsUtils::GetCachedColor( skin, textColor, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG9 );
	TRgb highlightColor; // text color when highlighted
	AknsUtils::GetCachedColor( skin, highlightColor, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG11 );

	CFormattedCellListBoxData::TColors colors;
	colors.iText = textColor;
	colors.iHighlightedText = highlightColor;
	iGrid->ItemDrawer()->FormattedCellData()->SetSubCellColorsL( 0, colors );
	iGrid->ItemDrawer()->FormattedCellData()->SetSubCellColorsL( 1, colors );
	iGrid->ItemDrawer()->FormattedCellData()->SetSubCellColorsL( 3, colors );

	TInt ItemsCount = iGrid->Model()->ItemTextArray()->MdcaCount();
 
	if(ItemsCount > MySetIndex && MySetIndex >= 0)
		iGrid->SetCurrentItemIndex(MySetIndex);
	else if(ItemsCount > 0)
		iGrid->SetCurrentItemIndex(0);
 
		
	iGrid->SetListBoxObserver(this);
	iGrid->MakeVisible( ETrue );
	iGrid->SetFocus( ETrue );
	iGrid->ActivateL();
	iGrid->DrawNow();
	
	//start converting only if photos are available
	if( ImageCount()>0 )
		iImageConvertor->StartImageConversionL(iFiles[iArrayIndex]);
	
	}
CDesCArray* CImageGridDispaly::GetArrayL(CArrayPtr<CGulIcon>* aIcon,const TSize& aIconsize)
{	
	CDesCArrayFlat* cArray = new(ELeave)CDesCArrayFlat(1);
	CleanupStack::PushL(cArray);
			
	// Delete data from array
	if ( iGrid->GridModel()->NumberOfData() > 0 )
	{
		cArray->Delete( 0, iGrid->GridModel()->NumberOfData() );
	}
	iGrid->HandleItemRemovalL();

	// Create text which is added to the grid.
	TBuf< 256> cellText;
	_LIT(KFormatString,"%d\t%S");
	TBuf< 15 > cellTextFormat(KFormatString);
		
	// The number of photos available
	TInt numberOfData = ImageCount();
		
	// Add the item to the last index
    for ( TInt loop = 0; loop < numberOfData; loop++ )
		{
		TFileName aFilename;
		PlainImageName(aFilename,loop);
		cellText.Format( cellTextFormat,loop, &aFilename );
		cArray->AppendL( cellText );
		}
	
	// Inform list box that data was added.
	iGrid->HandleItemAdditionL();
	
	_LIT(KMBMFile,"c:\\data\\images\\picture.mbm" );
	CFbsBitmap* aDefaultBitmap = new (ELeave) CFbsBitmap;
	RDebug::Printf("Memory Leak Find Address of aDefaultBitmap = %x",aDefaultBitmap);
	CleanupStack::PushL(aDefaultBitmap);
	User::LeaveIfError(aDefaultBitmap->Load(KMBMFile, 0));
	
	CFbsBitmap* mask = NULL;
	
	// Determinate icon size
	TSize iconSize;
	iconSize.iWidth = iSizeOfCell.iWidth/2;
	iconSize.iHeight = iSizeOfCell.iHeight/2;

	//Initializes the icon to the given size.
	//Note that this call sets the sizes of both bitmap and mask 
	AknIconUtils::SetSize( aDefaultBitmap, iconSize );
	
	//TODO Delete
	// Ownership of bitmap is passed to GulIcon
	iDefaultGulIcon = CGulIcon::NewL(aDefaultBitmap, mask);
	RDebug::Printf("Memory Leak Find Address of iDefaultGulIcon = %x",iDefaultGulIcon);
		
	for ( TInt loop = 0; loop < numberOfData; loop++ )
		{
		// Append the icon to icon array
		aIcon->AppendL(iDefaultGulIcon);
		}
	
	CleanupStack::Pop(aDefaultBitmap);	 
	CleanupStack::Pop(cArray);
	
	return cArray;
}

void CImageGridDispaly::UpdateGrid(CFbsBitmap& aBitMap)
	{
	CFbsBitmap* mask = NULL;
					  
	// Determinate icon size
	TSize iconSize;
	iconSize.iWidth = iSizeOfCell.iWidth/2;
	iconSize.iHeight = iSizeOfCell.iHeight/2;
	
	//Initializes the icon to the given size.
	//Note that this call sets the sizes of both bitmap and mask 
	AknIconUtils::SetSize( &aBitMap, iconSize );
	
	// Remove the old icon at index iArrayIndex from Icon array
	CArrayPtr<CGulIcon>* arrayIcons = iGrid->ItemDrawer()->ColumnData()->IconArray();
	arrayIcons->Delete(iArrayIndex);
	
	
	CGulIcon* aGulIcon =  CGulIcon::NewL(&aBitMap, mask);
	RDebug::Printf("Memory Leak Find Address of aGulIcon = %x",aGulIcon);
	CleanupStack::PushL(aGulIcon);
	// Append the icon to icon array
	iArrayicons->InsertL(iArrayIndex, aGulIcon);
	
	if((ImageCount()-1)>iArrayIndex)
		{
		iImageConvertor->StartImageConversionL(iFiles[++iArrayIndex]);
		}
	CleanupStack::Pop(aGulIcon);
	iGrid->DrawNow();
	
	}
void CImageGridDispaly::ShowErrorMessage(TInt aError)
	{
	iErrorStatus = ETrue;			
	_LIT(KImageUpload,"S60 Photo Browser" );
	TBuf< 256> cellText;
	_LIT(KFormatString,"Failed to display image = %d");
	cellText.Format( KFormatString,aError );
	iEikonEnv->InfoWinL(KImageUpload,cellText);
	}

// -----------------------------------------------------------------------------
// CImageGridDispaly::HandleListBoxEventL
// Called by the framework whenever a grid event occurs for which this container
// is an observer.
// @param aListBoxEvent The type of event which occured
// -----------------------------------------------------------------------------    
void CImageGridDispaly::HandleListBoxEventL(CEikListBox* aListBox,TListBoxEvent aListBoxEvent)
	{
	iGrid->SetCurrentItemIndex(aListBox->CurrentItemIndex());
	}

void CImageGridDispaly::ReadImageDirectoryL(TFileName& aFilepath)
	{
	RFs& rfs = iEikonEnv->FsSession();
	CDir* fileList = NULL;

	User::LeaveIfError(rfs.GetDir(aFilepath, KEntryAttNormal, ESortByName,
			           fileList));

	for (TInt i = 0; i < fileList->Count(); i++)
		{
		// Read only files to array
		if (!fileList->operator[](i).IsDir())
			{
			TFileName filename;
			filename.Append(aFilepath);
			filename.Append(fileList->operator[](i).iName);
			filename.LowerCase();
			// We support only JPG, BMP,  GIF
			if (filename.Find(_L(".jpg")) != KErrNotFound || filename.Find(_L(".jpeg")) != KErrNotFound 
				|| filename.Find(_L(".bmp")) != KErrNotFound || filename.Find(_L(".gif")) != KErrNotFound)
				{
				iFiles.Append(filename);
				}
			}
		}

	delete fileList;
	}

TInt CImageGridDispaly::ImageCount()
	{
	return iFiles.Count();
	}
void CImageGridDispaly::ImageName(TFileName& aFilename, TInt aIndex)
	{
	aFilename.Copy(iFiles[aIndex]);
	if (aFilename.Find(_L("\\")) > -1)
		{
		aFilename.Delete(0, aFilename.LocateReverse('\\') + 1);
		}
	}

void CImageGridDispaly::PlainImageName(TFileName& aFilename, TInt aIndex)
	{
	aFilename.Copy(iFiles[aIndex]);
	if (aFilename.Find(_L("\\")) > -1)
		{
		aFilename.Delete(0, aFilename.LocateReverse('\\') + 1);
		}
	if (aFilename.Find(_L(".")) > -1)
		{
		aFilename.SetLength(aFilename.Find(_L(".")));
		}
	}
